import re
from collections import defaultdict
from util import HtmlReport, PathUtil, Ipc
import env.Env as Env
from datetime import datetime
import os


def find_failed_ips(log_file_path, host, login_error_count):
    filtered_ips = []
    current_year = datetime.now().year
    try:
        with open(log_file_path, 'r', encoding="utf-8") as file:
            log_lines = file.readlines()
    except FileNotFoundError:
        print(f"错误：未找到文件 {log_file_path}")
    else:
        ip_minute_counts = defaultdict(lambda: defaultdict(int))
        ip_minute_first_time = defaultdict(lambda: defaultdict(str))
        ip_access_logs = defaultdict(list)

        for line in log_lines:
            match = re.search(
                r'(\w{3} \d{1,2} \d{2}:\d{2}:\d{2}).*Failed password.*from (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', line)
            if match:
                date_str = match.group(1)
                ip = match.group(2)
                full_date = datetime.strptime(f"{current_year} {date_str}", '%Y %b %d %H:%M:%S')
                # 将 minute_key 转换为字符串
                minute_key = full_date.replace(second=0).strftime('%Y-%m-%d %H:%M')
                if ip_minute_first_time[ip][minute_key] == '':
                    ip_minute_first_time[ip][minute_key] = full_date.strftime('%Y-%m-%d %H:%M:%S')
                ip_minute_counts[ip][minute_key] += 1
                ip_access_logs[ip + minute_key].append(line.strip())

        for ip, minute_data in ip_minute_counts.items():
            for minute, count in minute_data.items():
                if count >= login_error_count:
                    filtered_ips.append({
                        "ip": ip,
                        "时间": ip_minute_first_time[ip][minute],
                        "错误次数": count,
                        "主机": host,
                        "详细记录": ip_access_logs[ip + minute]
                    })
                    print(f"IP: {ip}, 访问时间: {ip_minute_first_time[ip][minute]}, 错误访问次数: {count}")
    return filtered_ips


def generate_html_report(listinfo):
    flush_interval = Env.get_flush_interval("ssh")
    html = f"""
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="refresh" content="{flush_interval}">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>SSH错误访问报告</title>
        <style>
            body {{
                font-family: Arial, sans-serif;
                background-color: #f4f4f9;
                margin: 20px;
            }}
            h1 {{
                text-align: center;
                color: #333;
                margin-bottom: 20px;
            }}
            h2 {{
                color: #555;
                margin-top: 30px;
            }}
            table {{
                width: 100%;
                border-collapse: collapse;
                margin-top: 10px;
                box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
            }}
            th, td {{
                padding: 12px 15px;
                text-align: left;
                border-bottom: 1px solid #ddd;
            }}
            th {{
                background-color: #007BFF;
                color: white;
            }}
            tr:hover {{
                background-color: #f5f5f5;
            }}
            .modal {{
                display: none;
                position: fixed;
                z-index: 1;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
                overflow: auto;
                background-color: rgba(0,0,0,0.4);
            }}
            .modal-content {{
                background-color: #fefefe;
                margin: 15% auto;
                padding: 20px;
                border: 1px solid #888;
                width: 80%;
            }}
            .close {{
                color: #aaa;
                float: right;
                font-size: 28px;
                font-weight: bold;
            }}
            .close:hover,
            .close:focus {{
                color: black;
                text-decoration: none;
                cursor: pointer;
            }}
        </style>
    </head>
    <body>
        <h1>SSH错误访问报告</h1>
    """
    for host, ips in listinfo.items():
        html += f"<h2>{host}</h2>"
        html += "<table>"
        html += "<tr><th>ip</th><th>错误次数</th><th>时间</th></tr>"
        for ip_info in ips:
            ip = ip_info['ip']
            detailed_logs = '<br>'.join(ip_info['详细记录'])
            html += f"""
            <tr>
                <td><a href="#" onclick="showModal('{ip}', '{detailed_logs.replace("'", "\\'")}')">{ip}</a></td>
                <td>{ip_info['错误次数']}</td>
                <td>{ip_info['时间']}</td>
            </tr>
            """
        html += "</table>"

    html += """
        <div id="myModal" class="modal">
            <div class="modal-content">
                <span class="close">&times;</span>
                <h2 id="modalTitle"></h2>
                <pre id="modalContent"></pre>
            </div>
        </div>
        <script>
            function showModal(ip, logs) {
                var modal = document.getElementById('myModal');
                var title = document.getElementById('modalTitle');
                var content = document.getElementById('modalContent');

                title.innerHTML = 'IP ' + ip + ' 详细登录记录';
                content.innerHTML = logs.replace(/<br>/g, '\\n');

                modal.style.display = "block";

                var span = document.getElementsByClassName("close")[0];
                span.onclick = function() {
                    modal.style.display = "none";
                }

                window.onclick = function(event) {
                    if (event.target == modal) {
                        modal.style.display = "none";
                    }
                }
            }
        </script>
    </body>
    </html>
    """
    return html


def scan():
    listinfo = {}
    for item in Env.get_host_list():
        host = item["host"]
        cmd = "cat /var/log/secure"
        login_error_count = item["ssh_login_error_count_for_minute"]
        result = Ipc.shell_call_new(host=host, cmd=cmd)
        rootlog = PathUtil.get_root_path() + "/log/"
        if not os.path.exists(rootlog):
            os.makedirs(rootlog)
        log_file_path = PathUtil.get_root_path() + "/log/" + host + ".log"
        with open(log_file_path, 'w', encoding="utf-8") as file:
            file.write(result)
        failed_ips = find_failed_ips(log_file_path, host, login_error_count)
        listinfo[host] = failed_ips
    html_content = generate_html_report(listinfo)
    report_path = PathUtil.get_root_path() + "/report/ip_error_report.html"
    report_dir = os.path.dirname(report_path)
    if not os.path.exists(report_dir):
        os.makedirs(report_dir)
    with open(report_path, 'w', encoding="utf-8") as file:
        file.write(html_content)


if __name__ == "__main__":
    scan()
